0703. 数据流中的第 K 大元素【简单】
1. 📝 题目描述
设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。
请实现 KthLargest 类:
KthLargest(int k, int[] nums)使用整数k和整数流nums初始化对象。int add(int val)将val插入数据流nums后,返回当前数据流中第k大的元素。
示例 1:
txt
输入:
["KthLargest", "add", "add", "add", "add", "add"]
[[3, [4, 5, 8, 2]], [3], [5], [10], [9], [4]]
输出:[null, 4, 5, 5, 8, 8]
解释:
KthLargest kthLargest = new KthLargest(3, [4, 5, 8, 2]);
kthLargest.add(3); // 返回 4
kthLargest.add(5); // 返回 5
kthLargest.add(10); // 返回 5
kthLargest.add(9); // 返回 8
kthLargest.add(4); // 返回 81
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
示例 2:
txt
输入:
["KthLargest", "add", "add", "add", "add"]
[[4, [7, 7, 7, 7, 8, 3]], [2], [10], [9], [9]]
输出:[null, 7, 7, 7, 8]
解释:
KthLargest kthLargest = new KthLargest(4, [7, 7, 7, 7, 8, 3]);
kthLargest.add(2); // 返回 7
kthLargest.add(10); // 返回 7
kthLargest.add(9); // 返回 7
kthLargest.add(9); // 返回 81
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
提示:
0 <= nums.length <= 10^41 <= k <= nums.length + 1-10^4 <= nums[i] <= 10^4-10^4 <= val <= 10^4- 最多调用
add方法10^4次
2. 🫧 评价
s.1是手写最小堆s.2是利用内置的 datastructures-js 中的 MinPriorityQueue- Javascript 语言执行环境中内置了 datastructures-js 中的数据结构。
- “堆” 数据结构的特点和实现,在 TNotes.algorithms 知识库中有介绍。
3. 🎯 s.1 - 最小堆
js
/**
* @param {number} k
* @param {number[]} nums
*/
var KthLargest = function (k, nums) {
this.k = k
this.heap = []
// 初始化堆
for (const num of nums) {
this.add(num)
}
}
/**
* @param {number} val
* @return {number}
*/
KthLargest.prototype.add = function (val) {
// 向堆中添加元素
this.heap.push(val)
this.heapifyUp(this.heap.length - 1)
// 如果堆的大小超过k,移除最小元素
if (this.heap.length > this.k) {
this.heap[0] = this.heap[this.heap.length - 1]
this.heap.pop()
this.heapifyDown(0)
}
// 返回第k大的元素(堆顶)
return this.heap[0]
}
// 最小堆向上调整
KthLargest.prototype.heapifyUp = function (index) {
while (index > 0) {
const parentIndex = Math.floor((index - 1) / 2)
if (this.heap[index] >= this.heap[parentIndex]) {
break
}
;[this.heap[index], this.heap[parentIndex]] = [
this.heap[parentIndex],
this.heap[index],
]
index = parentIndex
}
}
// 最小堆向下调整
KthLargest.prototype.heapifyDown = function (index) {
while (index < this.heap.length) {
let minIndex = index
const leftChildIndex = index * 2 + 1
const rightChildIndex = index * 2 + 2
if (
leftChildIndex < this.heap.length &&
this.heap[leftChildIndex] < this.heap[minIndex]
) {
minIndex = leftChildIndex
}
if (
rightChildIndex < this.heap.length &&
this.heap[rightChildIndex] < this.heap[minIndex]
) {
minIndex = rightChildIndex
}
if (minIndex === index) {
break
}
;[this.heap[index], this.heap[minIndex]] = [
this.heap[minIndex],
this.heap[index],
]
index = minIndex
}
}
/**
* Your KthLargest object will be instantiated and called as such:
* var obj = new KthLargest(k, nums)
* var param_1 = obj.add(val)
*/1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
- 时间复杂度:
,其中 n 是添加元素的个数,每次添加操作的时间复杂度为 - 空间复杂度:
,堆中最多存储 k 个元素
4. 🎯 s.2 - 优先队列(更简洁)
js
/**
* @param {number} k
* @param {number[]} nums
*/
var KthLargest = function (k, nums) {
this.k = k
// 使用最小堆
this.minHeap = new MinPriorityQueue()
// 初始化堆
for (const num of nums) {
this.add(num)
}
}
/**
* @param {number} val
* @return {number}
*/
KthLargest.prototype.add = function (val) {
// 向堆中添加元素
this.minHeap.enqueue(val)
// 如果堆的大小超过k,移除最小元素
if (this.minHeap.size() > this.k) {
this.minHeap.dequeue()
}
// 返回第k大的元素(堆顶)
return this.minHeap.front()
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
- 时间复杂度:
,其中 n 是添加元素的个数,每次添加操作的时间复杂度为 - 空间复杂度:
,堆中最多存储 k 个元素